﻿
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Packaging;
using System.Reflection;
using System.Resources;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SharpSoft.WPF.Controls
{
    /// <summary>
    /// 帧图像
    /// </summary>
    [TemplatePart(Name = "image", Type = typeof(Image))]
    public class FrameImage : Control, IUriContext
    {
        static FrameImage()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(FrameImage), new FrameworkPropertyMetadata(typeof(FrameImage)));
        }
        public FrameImage()
        {
            this.Loaded += FrameImage_Loaded;
            this.Unloaded += FrameImage_Unloaded;
        }

        private void FrameImage_Unloaded(object sender, RoutedEventArgs e)
        {
            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {//控件卸载时解绑Rendering很重要，否则会导致资源不释放。
                CompositionTarget.Rendering -= CompositionTarget_Rendering;
            }
        }

        private void FrameImage_Loaded(object sender, RoutedEventArgs e)
        {
            if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
            {//设计时不渲染
                CompositionTarget.Rendering += CompositionTarget_Rendering;
            }
            this.OnFramerateChanged();
        }


        #region 成员 
        private Image image;
        private int roundCount = 0;//记录已经循环播放的次数
        /// <summary>
        /// 每一帧的时间间隔
        /// </summary>
        private TimeSpan interval;
        private DateTime lastTime;
        #endregion

        #region 实现

        private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            if (this.IsPlaying)
            {
                var curTime = DateTime.Now;
                var diff = curTime - lastTime;
                if (diff >= interval)
                {//与上一帧的时差已经超过了单帧时限
                    lastTime = curTime;
                    this.OnUpdate();
                }

            }
        }
        private void OnUpdate()
        {
            var frames = this.Source;
            if (frames == null || frames.Length == 0)
            {
                return;
            }
            if (this.RepeatBehavior.HasCount)
            {//指定次数
                if (roundCount >= this.RepeatBehavior.Count)
                {
                    this.OnCompleted();
                    return;
                }
            }
            else if (this.RepeatBehavior.HasDuration)
            {//指定时长
                var count = frames.Length;
                //计算当前已播放的所有帧数已经过的时间
                var elapsed = TimeSpan.FromMilliseconds(interval.TotalMilliseconds * count * roundCount + this.CurrentFrameIndex * interval.TotalMilliseconds);

                if (elapsed >= this.RepeatBehavior.Duration)
                {
                    this.OnCompleted();
                    return;
                }
            }

            nextFrame();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.image = (Image)this.GetTemplateChild("image");

            this.showCurrentFrame();
        }
        /// <summary>
        /// 移除图像控件中的图像
        /// </summary>
        private void removeImage()
        {
            if (this.image != null)
            {
                this.image.Source = null;
            }
        }
        /// <summary>
        /// 转到下一帧索引（不更新画面）
        /// </summary>
        private void nextFrame()
        {
            var frames = this.Source;
            if (frames == null || frames.Length == 0)
            {
                removeImage();
                return;
            }
            var index = this.CurrentFrameIndex;
            if (!PlayReverse)
            {
                index++;
                if (index > frames.Length - 1)
                {//超出最后一帧，重置索引
                    index = 0;
                }
                if (index == frames.Length - 1)
                { //达到最后一帧，累计循环次数
                    roundCount++;
                }
            }
            else
            {//逆序播放
                index--;
                if (index < 0)
                {//超出第一帧，重置索引
                    index = frames.Length - 1;
                }
                if (index == 0)
                {
                    roundCount++;
                }
            }
            this.CurrentFrameIndex = index;
        }

        /// <summary>
        /// 呈现当前帧图像
        /// </summary>
        private void showCurrentFrame()
        {
            var frames = this.Source;
            if (frames == null || frames.Length == 0)
            {
                removeImage();
                return;
            }
            var img = frames[this.CurrentFrameIndex];
            if (image != null)
            {
                image.Source = img;
            }
        }
        #endregion

        #region 方法
        /// <summary>
        /// 开始播放，等同于设置<see cref="IsPlaying"/>为<see cref="true"/>
        /// </summary>
        public void Play()
        {
            roundCount = 0;
            IsPlaying = true;
        }

        /// <summary>
        /// 暂停播放，等同于设置<see cref="IsPlaying"/>为<see cref="false"/>
        /// </summary>
        public void Pause()
        {
            IsPlaying = false;
        }
        /// <summary>
        /// 停止播放，设置<see cref="IsPlaying"/>为<see cref="false"/>并重置<see cref="CurrentFrameIndex"/>为0.
        /// </summary>
        public void Stop()
        {
            IsPlaying = false;
            if (!PlayReverse)
            {
                CurrentFrameIndex = 0;
            }
            else
            {
                CurrentFrameIndex = this.Source.Length - 1;
            }
        }

        /// <summary>
        /// 设置播放源为系统文件夹内的图片
        /// </summary>
        /// <param name="folderFullPath">文件夹绝对路径</param>
        /// <param name="seachPattern">用于搜索需要的文件，默认为搜索png类型图片</param>
        public ImageSource[] SetSourceFolder(string folderFullPath, string seachPattern = "*.png")
        {
            var files = System.IO.Directory.GetFiles(folderFullPath, seachPattern);
            List<ImageSource> bmps = new List<ImageSource>(files.Length);
            foreach (var item in files)
            {
                var bmp = new BitmapImage(new Uri(item));
                bmp.Freeze();
                bmps.Add(bmp);
            }
            this.Source = bmps.ToArray();
            return this.Source;
        }
        /// <summary>
        /// 设置设置播放源为资源文件目录内的文件
        /// </summary>
        /// <param name="assembly"></param>
        /// <param name="folder"></param>
        /// <returns></returns>
        public ImageSource[] SetSourceResourceFolder(Assembly assembly, string folder)
        {
            var allresnames = assembly.GetManifestResourceNames();
            List<ImageSource> bmps = new List<ImageSource>();

            foreach (string name in allresnames)
            {
                Dictionary<string, Stream> dic = new Dictionary<string, Stream>();
                Stream st = assembly.GetManifestResourceStream(name);
                try
                {
                    ResourceReader resourceReader;
                    try
                    {
                        resourceReader = new ResourceReader(st);
                    }
                    catch (Exception)
                    {//不是有效的项目资源
                        continue;
                    }
                    using (resourceReader)
                    {
                        foreach (DictionaryEntry resourceEntry in resourceReader)
                        {
                            if (resourceEntry.Key is string relpath)
                            {
                                if (resourceEntry.Value is Stream stream)
                                {
                                    var f = System.IO.Path.GetDirectoryName(relpath).Replace("\\", "/");
                                    Uri u1 = new Uri(f, UriKind.Relative);
                                    if (folder.StartsWith("/"))
                                    {//去掉头部的斜杠
                                        folder = folder.TrimStart('/');
                                    }
                                    var u2 = new Uri(folder, UriKind.Relative);
                                    if (Uri.Compare(u1, u2, UriComponents.Path, UriFormat.UriEscaped, StringComparison.OrdinalIgnoreCase) == 0)
                                    {
                                        dic.Add(relpath, stream);
                                    }
                                }
                            }
                        }
                    }
                }
                catch (ArgumentException ex)
                {
                    throw new Exception("读取资源清单出错。", ex);
                }
                string[] keys = new string[dic.Count];
                var i = 0;
                foreach (var item in dic.Keys)
                {
                    keys[i] = item;
                    i++;
                }
                Array.Sort(keys);
                foreach (var item in keys)
                {
                    var bmp = new BitmapImage();
                    bmp.BeginInit();
                    bmp.StreamSource = dic[item];
                    bmp.EndInit();
                    bmp.Freeze();
                    bmps.Add(bmp);
                }
            }

            this.Source = bmps.ToArray();
            return this.Source;
        }

        #endregion

        #region 事件
        /// <summary>
        /// 在帧动画按照指定的行为播放完成后触发，注意：主动停止动画将不会触发这个事件。
        /// </summary>
        public event RoutedEventHandler Completed
        {
            add { AddHandler(CompletedEvent, value); }
            remove { RemoveHandler(CompletedEvent, value); }
        }

        public static readonly RoutedEvent CompletedEvent = EventManager.RegisterRoutedEvent(
        "Completed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FrameImage));

        protected virtual void OnCompleted()
        {
            IsPlaying = false;

            if (this.FillBehavior == FillBehavior.Stop)
            {//如果完成后的行为指定为停止则更新图像为第一帧。否则保持当前帧。 
                if (!PlayReverse)
                {
                    CurrentFrameIndex = 0;

                }
                else
                {
                    if (Source != null && this.Source.Length > 0)
                    {
                        CurrentFrameIndex = this.Source.Length - 1;
                    }

                }
            }
            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = FrameImage.CompletedEvent;
            this.RaiseEvent(args);
        }

        /// <summary>
        /// 在当前帧改变后触发
        /// </summary>
        public event RoutedEventHandler CurrentFrameIndexChanged
        {
            add { AddHandler(CurrentFrameIndexChangedEvent, value); }
            remove { RemoveHandler(CurrentFrameIndexChangedEvent, value); }
        }

        public static readonly RoutedEvent CurrentFrameIndexChangedEvent = EventManager.RegisterRoutedEvent(
        "CurrentFrameIndexChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FrameImage));

        protected virtual void OnCurrentFrameIndexChanged()
        {
            this.showCurrentFrame();
            RoutedEventArgs args = new RoutedEventArgs();
            args.RoutedEvent = FrameImage.CurrentFrameIndexChangedEvent;
            this.RaiseEvent(args);
        }


        #endregion

        #region 属性

        /// <summary>
        /// 图片源
        /// </summary>
        public ImageSource[] Source
        {
            get { return (ImageSource[])GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(ImageSource[]), typeof(FrameImage), new PropertyMetadata(null, new PropertyChangedCallback(OnSourceChanged)));

        private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is FrameImage fi)
            {
                fi.OnSourceChanged();
            }
        }

        protected virtual void OnSourceChanged()
        {

            if (!PlayReverse)
            {
                CurrentFrameIndex = 0;
                this.showCurrentFrame();

            }
            else
            {
                if (Source != null && this.Source.Length > 0)
                {
                    CurrentFrameIndex = this.Source.Length - 1;
                }

            }

            this.IsPlaying = this.AutoPlay;//源改变后是否自动播放
        }


        /// <summary>
        /// 帧率
        /// </summary>
        public int Framerate
        {
            get { return (int)GetValue(FramerateProperty); }
            set { SetValue(FramerateProperty, value); }
        }

        public static readonly DependencyProperty FramerateProperty =
            DependencyProperty.Register("Framerate", typeof(int), typeof(FrameImage), new PropertyMetadata(24, new PropertyChangedCallback(OnFramerateChanged)));

        private static void OnFramerateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is FrameImage fi)
            {
                fi.OnFramerateChanged();
            }
        }
        /// <summary>
        /// 在帧率变化后调用
        /// </summary>
        protected virtual void OnFramerateChanged()
        {
            interval = TimeSpan.FromMilliseconds(1000d / this.Framerate);
        }


        /// <summary>
        /// 是否正在播放
        /// </summary>
        public bool IsPlaying
        {
            get { return (bool)GetValue(IsPlayingProperty); }
            set { SetValue(IsPlayingProperty, value); }
        }

        public static readonly DependencyProperty IsPlayingProperty =
            DependencyProperty.Register("IsPlaying", typeof(bool), typeof(FrameImage), new PropertyMetadata(false, new PropertyChangedCallback(OnIsPlayingChanged)));

        private static void OnIsPlayingChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is FrameImage fi)
            {
                fi.OnIsPlayingChanged();
            }
        }

        protected virtual void OnIsPlayingChanged()
        {
            //if (this.IsPlaying)
            //{
            //    if (this.CurrentFrameIndex == 0)
            //    {//从第一帧开始播放
            //        this.roundCount = 0;
            //    }
            //}
        }




        /// <summary>
        /// 获取或设置帧图形播放的重复行为，默认为永远重复。
        /// </summary> 
        public RepeatBehavior RepeatBehavior
        {
            get { return (RepeatBehavior)GetValue(RepeatBehaviorProperty); }
            set { SetValue(RepeatBehaviorProperty, value); }
        }

        public static readonly DependencyProperty RepeatBehaviorProperty =
            DependencyProperty.Register("RepeatBehavior", typeof(RepeatBehavior), typeof(FrameImage), new PropertyMetadata(RepeatBehavior.Forever));


        /// <summary>
        /// 指定帧动画播放完成后的行为（保持最后一帧或停止）
        /// </summary>
        public FillBehavior FillBehavior
        {
            get { return (FillBehavior)GetValue(FillBehaviorProperty); }
            set { SetValue(FillBehaviorProperty, value); }
        }

        public static readonly DependencyProperty FillBehaviorProperty =
            DependencyProperty.Register("FillBehavior", typeof(FillBehavior), typeof(FrameImage), new PropertyMetadata(FillBehavior.Stop));


        /// <summary>
        /// 当前帧索引
        /// </summary>
        public int CurrentFrameIndex
        {
            get { return (int)GetValue(CurrentFrameIndexProperty); }
            set { SetValue(CurrentFrameIndexProperty, value); }
        }

        public static readonly DependencyProperty CurrentFrameIndexProperty =
            DependencyProperty.Register("CurrentFrameIndex", typeof(int), typeof(FrameImage), new PropertyMetadata(0, new PropertyChangedCallback(OnCurrentFrameIndexChanged)));

        private static void OnCurrentFrameIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is FrameImage fi)
            {
                fi.OnCurrentFrameIndexChanged();
            }
        }


        /// <summary>
        /// 设置在图片源修改后是否自动播放
        /// </summary>
        public bool AutoPlay
        {
            get { return (bool)GetValue(AutoPlayProperty); }
            set { SetValue(AutoPlayProperty, value); }
        }

        public static readonly DependencyProperty AutoPlayProperty =
            DependencyProperty.Register("AutoPlay", typeof(bool), typeof(FrameImage), new PropertyMetadata(false));



        /// <summary>
        /// 设置图片的拉伸方式
        /// </summary>
        public Stretch Stretch
        {
            get { return (Stretch)GetValue(StretchProperty); }
            set { SetValue(StretchProperty, value); }
        }

        public static readonly DependencyProperty StretchProperty =
            DependencyProperty.Register("Stretch", typeof(Stretch), typeof(FrameImage), new PropertyMetadata(Stretch.Fill));


        /// <summary>
        /// 设置图片拉伸的方向
        /// </summary>
        public StretchDirection StretchDirection
        {
            get { return (StretchDirection)GetValue(StretchDirectionProperty); }
            set { SetValue(StretchDirectionProperty, value); }
        }


        public static readonly DependencyProperty StretchDirectionProperty =
            DependencyProperty.Register("StretchDirection", typeof(StretchDirection), typeof(FrameImage), new PropertyMetadata(StretchDirection.Both));

        /// <summary>
        /// 播放时逆序
        /// </summary>
        public bool PlayReverse { get; set; } = false;

        ///// <summary>
        ///// 资源目录
        ///// </summary>
        //public Uri ResourceFolder
        //{
        //    get { return (Uri)GetValue(ResourceFolderProperty); }
        //    set { SetValue(ResourceFolderProperty, value); }
        //}

        //public static readonly DependencyProperty ResourceFolderProperty =
        //    DependencyProperty.Register("ResourceFolder", typeof(Uri), typeof(FrameImage), new PropertyMetadata(null));

        //protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        //{
        //    base.OnPropertyChanged(e);
        //    if (e.Property == ResourceFolderProperty)
        //    {
        //        //SetSourceResourceFolder();
        //        //      Application.GET 
        //        // System.Windows.Navigation.BaseUriHelper.GetResolvedUri(baseUri, uri)
        //        if (this.ResourceFolder == null)
        //        {
        //            this.Source = null;
        //        }
        //        else
        //        {
        //            var uri = new Uri(BaseUriHelper.GetBaseUri(this), this.ResourceFolder);
        //            var ass = Global.GetAssemblyFromPackUri(uri);
        //            var list = Global.GetStreamResourcesManifest(ass);
        //            foreach (var item in list)
        //            {
        //                var dir = System.IO.Path.GetDirectoryName(item);
        //                dir = dir.Replace('\\', '/');
        //                Uri.Compare(this.res)//20200607 赶时间  暂时不写了

        //            }
        //        }

        //    }
        //}

        public Uri BaseUri { get; set; }

        #endregion
    }
}
